#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>

#define DTSKEY_CNT      1
#define DTSKEY_NAME     "mykey"
#define IRQ_CNT         6

/*
 * 中断处理服务
 */
static irqreturn_t button_irq(int irq, void *dev_id)
{
    printk("%s enter, irq: %d, %s\n", __func__, irq, (char *)dev_id);
    return 0;
}

/*
 * 当驱动和硬件信息匹配成功之后，就会调用probe函数，驱动所有的资源的注册和初始化全部放在probe函数中
 */
static int button_probe(struct platform_device *pdev)
{
      int ret = 0, i = 0;
      int num_irq = 0;
      struct device *dev = &pdev->dev;
      char *key_name;

      printk("%s enter.\n", __func__);

      if (!dev->of_node) {
            dev_err(dev, "no device tree node\n");
            return -EINVAL;
       }

      if(pdev->name != NULL){
            printk("platform device name %s",pdev->name);   // mykey
      }

      for(i = 0; i< IRQ_CNT; i ++){
            // 1. 获取中断资源
            ret = platform_get_irq(pdev, i);
            if (ret <= 0) {
                dev_err(&pdev->dev, "cannot find irq index %d\n",i);
                return ret;
            }

            key_name = kasprintf(GFP_KERNEL, "key-%d", i+1);

            // 2. 注册中断服务 中断触发类型设置为0，则使用设备树中的配置
            ret = devm_request_irq(&pdev->dev, ret, button_irq, 0, key_name, key_name);
            if (ret != 0) {
                dev_err(&pdev->dev, "cannot claim irq %d\n", ret);
                return ret;
            }
      }
     return 0;
}

/*
 * 硬件信息被移除了，或者驱动被卸载了，全部要释放，释放资源的操作就放在该函数中
 */
static int button_remove(struct platform_device * pdev)
{
    printk("button  driver exit\n");
    return 0;
}


/*
 * 用于设备树匹配
 */
static const struct of_device_id button_dt_match[] = {
    { .compatible = DTSKEY_NAME, },
    {},
};

/*
 * platform驱动
 */
static struct platform_driver button_driver = {
    .probe = button_probe,
    .remove = button_remove,

    .driver = {
        .name = DTSKEY_NAME,
        .of_match_table = button_dt_match,  // 匹配列表
    }
};

/*
 * platform驱动模块入口
 */
static int button_drv_init(void)
{
   // platform驱动注册
   int err = platform_driver_register(&button_driver);
   if (err) {
          printk("platform driver registered failed\n");
   } else {
          printk("platform driver registered successfully\n");
   }
   return err;
}

/*
 * platform驱动模块出口
 */
static void __exit button_drv_exit(void)
{
    printk("platform driver unregistered\n");
    // platform驱动卸载
    platform_driver_unregister(&button_driver);
}

module_init(button_drv_init);
module_exit(button_drv_exit);
MODULE_LICENSE("GPL");
